package jmine.tec.hydra.web.pages.especificacao.agendamento;

import static jmine.tec.hydra.web.HydraWebMessages.ERRO_SCHEDULED_SPECIFICATION_PREENCHER_DATA;
import static jmine.tec.hydra.web.HydraWebMessages.ERRO_SCHEDULED_SPECIFICATION_SEM_REQUESTS;
import static jmine.tec.hydra.web.HydraWebMessages.INFO_SCHEDULED_SPECIFICATION_EXECUTADA_SUCESSO;
import images.ImageResources;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import jmine.tec.hydra.HydraController;
import jmine.tec.hydra.api.HydraRequest;
import jmine.tec.hydra.dao.HydraRequestDAO;
import jmine.tec.hydra.dao.HydraScheduledSpecificationDAO;
import jmine.tec.hydra.domain.HydraRequestImpl;
import jmine.tec.hydra.domain.HydraSystem;
import jmine.tec.hydra.domain.specification.HydraScheduledSpecification;
import jmine.tec.hydra.web.pages.requisicao.ConsultaDetalheIntegracaoRequisicao;
import jmine.tec.web.exception.WebWicketException;
import jmine.tec.web.pages.HelpTextMessages;
import jmine.tec.web.wicket.component.MapsWicketDateTextField;
import jmine.tec.web.wicket.component.autocomplete.NaturalKeyAutocomplete;
import jmine.tec.web.wicket.component.button.ActionSubmitLink;
import jmine.tec.web.wicket.pages.Template;
import jmine.tec.web.wicket.spring.SpringBeanReference;

import org.apache.wicket.ResourceReference;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.SubmitLink;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.image.Image;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.hibernate.LockMode;

import bancosys.tec.exception.LocalizedMessageHolder;
import bancosys.tec.exception.MessageCreator;
import bancosys.tec.persist.dao.BaseDAO;
import bancosys.tec.persist.dao.BaseDAOFactory;
import bancosys.tec.persist.dao.BeanNotFoundException;
import bancosys.tec.security.annotation.Secure;
import bancosys.tec.security.authorization.UrlPermission;
import bancosys.tec.utils.date.Date;
import bancosys.tec.utils.date.DateUtils;

/**
 * Tela de consulta e execução das integrações hydra de agendamento.
 * 
 * @author Renan Kuroki
 * @created 06/01/2011
 * @deprecated use jmine.tec.scheduling
 */
@Secure(id = "URL_LIST_INTEGRACAO_AGENDAMENTO_ESPECIFICACAO", permissionType = UrlPermission.class)
@Deprecated
public class ConsultaIntegracaoEspecificacaoAgendamento extends Template {

    protected static final int INITIAL_WIDTH_MODAL = 1000;

    protected static final int INITIAL_HEIGHT_MODAL = 350;

    private Form<HydraScheduledSpecification> form = null;

    @SpringBean(name = "hydraController")
    private HydraController hydraController;

    private List<HydraScheduledSpecificationRowData> hydraScheduledSpecificationList = new ArrayList<HydraScheduledSpecificationRowData>();

    /**
     * Construtor.
     */
    public ConsultaIntegracaoEspecificacaoAgendamento() {
        super();
        HydraScheduledSpecificationDAO dao = this.hydraController.getDAOFactory().getDAOByClass(HydraScheduledSpecificationDAO.class);
        List<HydraScheduledSpecification> listaHydraScheduledSpecification = dao.findAll();
        this.hydraScheduledSpecificationList = this.convertHydraScheduledSpecificationList(listaHydraScheduledSpecification);
        this.initForm();
    }

    /**
     * Inicializa o form.
     */
    private void initForm() {
        this.form = new Form<HydraScheduledSpecification>("mainForm") {
            @Override
            protected void onSubmit() {
                ConsultaIntegracaoEspecificacaoAgendamento.this.submitForm();
            }
        };
        this.form.add(new FeedbackPanel("feedback").setOutputMarkupId(true));

        BaseDAO<HydraScheduledSpecification> dao = this.hydraController.getDAOFactory().getGenericDAO(HydraScheduledSpecification.class);
        HydraScheduledSpecification hydraScheduledSpecification = dao.createBean();
        this.form.setModel(new Model<HydraScheduledSpecification>(hydraScheduledSpecification));

        NaturalKeyAutocomplete<HydraSystem> hydraSystemAutoComplete = new NaturalKeyAutocomplete<HydraSystem>(HydraSystem.class, "sistema");
        hydraSystemAutoComplete.setModel(new PropertyModel<HydraSystem>(hydraScheduledSpecification, "system"));
        this.form.add(hydraSystemAutoComplete);

        this.form.add(new TextField<String>("acao", new PropertyModel<String>(hydraScheduledSpecification, "action")));

        ListView<HydraScheduledSpecificationRowData> hydraScheduledSpecificationListView =
                new ListView<HydraScheduledSpecificationRowData>("hydraScheduledSpecificationList",
                        new PropertyModel<List<HydraScheduledSpecificationRowData>>(this, "hydraScheduledSpecificationList")) {

                    @Override
                    protected void populateItem(final ListItem<HydraScheduledSpecificationRowData> item) {
                        final HydraScheduledSpecificationRowData hydraScheduledSpecRowData = item.getModelObject();
                        final CheckBox lstSelecaoScheduledSpecification =
                                new CheckBox("lstSelecaoScheduledSpecification", new PropertyModel<Boolean>(hydraScheduledSpecRowData,
                                        "isSelecionado"));
                        lstSelecaoScheduledSpecification.setOutputMarkupId(true);
                        lstSelecaoScheduledSpecification.add(new AjaxFormComponentUpdatingBehavior("onchange") {
                            @Override
                            protected void onUpdate(AjaxRequestTarget target) {
                                if (lstSelecaoScheduledSpecification.getConvertedInput()) {
                                    item.get("lstTxtDataExecucao").setEnabled(true);
                                    target.addComponent(item.get("lstTxtDataExecucao"));
                                    target.focusComponent(item.get("lstTxtDataExecucao"));
                                } else {
                                    item.get("lstTxtDataExecucao").setEnabled(false);
                                    target.addComponent(item.get("lstTxtDataExecucao"));
                                }
                            }
                        });
                        item.add(lstSelecaoScheduledSpecification);
                        item.add(new Label("lstSistema", new PropertyModel<String>(hydraScheduledSpecRowData,
                                "scheduledSpecification.system")));
                        item.add(new Label("lstAcao", new PropertyModel<String>(hydraScheduledSpecRowData, "scheduledSpecification.action")));
                        item.add(new Label("lstStatus", new PropertyModel<String>(hydraScheduledSpecRowData, "status")));
                        item.add(new Label("lstEmissor", new PropertyModel<String>(hydraScheduledSpecRowData, "emissor")));
                        item.add(new Label("lstCodificacao", new PropertyModel<String>(hydraScheduledSpecRowData,
                                "scheduledSpecification.encodeScript.mnemonico")));
                        item.add(new Label("lstModelo", new PropertyModel<String>(hydraScheduledSpecRowData,
                                "scheduledSpecification.template.mnemonico")));

                        MapsWicketDateTextField lstTxtDataExecucao =
                                MapsWicketDateTextField.forDatePattern("lstTxtDataExecucao", new PropertyModel<Date>(
                                        hydraScheduledSpecRowData, "dataExecucao"), false, true);
                        lstTxtDataExecucao.add(new AjaxFormComponentUpdatingBehavior("onchange") {
                            @Override
                            protected void onUpdate(AjaxRequestTarget target) {
                                // Método implementado para que possa ser atualizado o valor alterado via AJAX;
                            }
                        });
                        lstTxtDataExecucao.setEnabled(false);
                        item.add(lstTxtDataExecucao);

                        final ModalWindow modalPanelDetalhe = new ModalWindow("modalPanelDetalhe") {
                            @Override
                            public void show(AjaxRequestTarget target) {
                                ModalPanelDetalheEspecificacaoAgendamento modal =
                                        (ModalPanelDetalheEspecificacaoAgendamento) this.getContent();
                                SpringBeanReference<BaseDAOFactory> daoFactoryRef = SpringBeanReference.forName("daoFactory");

                                HydraScheduledSpecificationRowData scheduledSpecRowData = modal.getScheduledSpecRowData();
                                try {
                                    scheduledSpecRowData.setScheduledSpecification(daoFactoryRef.get()
                                            .getDAOByClass(HydraScheduledSpecificationDAO.class)
                                            .findByPk(scheduledSpecRowData.getScheduledSpecification().getPk()));
                                } catch (BeanNotFoundException e) {
                                    // não ocorrerá
                                }
                                super.show(target);
                            }

                        };
                        modalPanelDetalhe.setInitialWidth(INITIAL_WIDTH_MODAL);
                        modalPanelDetalhe.setInitialHeight(INITIAL_HEIGHT_MODAL);
                        modalPanelDetalhe.setContent(new ModalPanelDetalheEspecificacaoAgendamento(modalPanelDetalhe.getContentId(),
                                hydraScheduledSpecRowData));
                        modalPanelDetalhe.setTitle("Detalhe Especificação");
                        item.add(modalPanelDetalhe);

                        AjaxLink<HydraScheduledSpecificationRowData> detalheHydraSchedule =
                                new AjaxLink<HydraScheduledSpecificationRowData>("lstBtnDetalheScheduledSpecification") {
                                    @Override
                                    public void onClick(AjaxRequestTarget target) {
                                        modalPanelDetalhe.show(target);
                                    }

                                };
                        detalheHydraSchedule.add(new Image("imgDetalheHydraSchedule", new ResourceReference(ImageResources.class,
                                "magnifier.png")));
                        item.add(detalheHydraSchedule);

                        AjaxLink<HydraScheduledSpecificationRowData> requestHydraSchedule =
                                new AjaxLink<HydraScheduledSpecificationRowData>("lstBtnGoRequestsSchdSpec") {
                                    @Override
                                    public void onClick(AjaxRequestTarget target) {
                                        try {
                                            HydraRequestImpl hydraRequest = hydraScheduledSpecRowData.getUltimaRequisicao();
                                            this.setResponsePage(new ConsultaDetalheIntegracaoRequisicao(hydraRequest.getPk(), this
                                                    .getPage()));
                                        } catch (WebWicketException e) {
                                            this.error(e.getLocalizedMessage());
                                            target.addComponent(ConsultaIntegracaoEspecificacaoAgendamento.this.form.get("feedback"));
                                        }
                                    }
                                };
                        requestHydraSchedule.add(new Image("imgRequestsHydraSchedule", new ResourceReference(ImageResources.class,
                                "file.png")));
                        item.add(requestHydraSchedule);
                    }
                };
        hydraScheduledSpecificationListView.setOutputMarkupId(true);
        this.add(hydraScheduledSpecificationListView);

        SubmitLink btnExecutar = new ActionSubmitLink("btnExecutar") {
            @Override
            public void onAction() {
                ConsultaIntegracaoEspecificacaoAgendamento.this.executarScheduledSpecification();
                this.setResponsePage(new ConsultaIntegracaoEspecificacaoAgendamento());
            }
        };
        this.form.add(btnExecutar);

        this.add(this.form);
    }

    /**
     * Rodado no submit do form.
     */
    private void submitForm() {
        HydraScheduledSpecificationDAO dao = this.hydraController.getDAOFactory().getDAOByClass(HydraScheduledSpecificationDAO.class);
        HydraScheduledSpecification hydraScheduledSpecification = this.form.getModelObject();
        List<HydraScheduledSpecification> listaHydraScheduledSpecification =
                dao.findBySystemActionLike(hydraScheduledSpecification.getSystem(), hydraScheduledSpecification.getAction());
        this.hydraScheduledSpecificationList = this.convertHydraScheduledSpecificationList(listaHydraScheduledSpecification);
    }

    /**
     * Método que executa as HydraScheduledSpecification selecionadas na tela, na data especificada.
     */
    protected void executarScheduledSpecification() {
        for (HydraScheduledSpecificationRowData hydraScheduledSpecRow : this.hydraScheduledSpecificationList) {
            if (hydraScheduledSpecRow.getIsSelecionado()) {
                try {
                    hydraScheduledSpecRow.executar();
                    LocalizedMessageHolder msg =
                            INFO_SCHEDULED_SPECIFICATION_EXECUTADA_SUCESSO.create(hydraScheduledSpecRow.getScheduledSpecification()
                                    .getSystem(), hydraScheduledSpecRow.getScheduledSpecification().getAction(), DateUtils
                                    .dateToStringDDMMYYYY(hydraScheduledSpecRow.getDataExecucao()));
                    ConsultaIntegracaoEspecificacaoAgendamento.this.info(msg.getMessage());
                } catch (WebWicketException e) {
                    ConsultaIntegracaoEspecificacaoAgendamento.this.error(e.getLocalizedMessage());
                }
            }
        }
    }

    /**
     * @return the hydraScheduledSpecificationList
     */
    public List<HydraScheduledSpecificationRowData> getHydraScheduledSpecificationtList() {
        return this.hydraScheduledSpecificationList;
    }

    /**
     * @param hydraScheduledSpecificationList the hydraScheduledSpecificationList to set
     */
    public void setHydraScheduledSpecificationList(List<HydraScheduledSpecificationRowData> hydraScheduledSpecificationList) {
        this.hydraScheduledSpecificationList = hydraScheduledSpecificationList;
    }

    /**
     * Cria uma lista de {@link HydraScheduledSpecificationRowData} a partir de uma lista de {@link HydraScheduledScheduledSpecification}.
     * 
     * @param listHydraScheduledSpecification the hydraScheduledSpecificationList to set
     * @return uma lista de {@link HydraScheduledSpecificationRowData}
     */
    private List<HydraScheduledSpecificationRowData> convertHydraScheduledSpecificationList(
            List<HydraScheduledSpecification> listHydraScheduledSpecification) {
        List<HydraScheduledSpecificationRowData> listHydraScheduledSpecificationRowData =
                new ArrayList<HydraScheduledSpecificationRowData>();
        for (HydraScheduledSpecification hydraScheduledSpec : listHydraScheduledSpecification) {
            listHydraScheduledSpecificationRowData.add(new HydraScheduledSpecificationRowData(hydraScheduledSpec, Boolean.FALSE));
        }
        return listHydraScheduledSpecificationRowData;
    }

    /**
     * Inner Class auxiliar para criação da lista de {@link HydraScheduledSpecification}, com opção especificar uma data de executacao.
     * 
     * @author Renan Kuroki
     * @created 06/01/2011
     */
    protected class HydraScheduledSpecificationRowData implements Serializable {

        private static final String ATIVADO = "Ativado";

        private static final String DESATIVADO = "Desativado";

        /**
         * Construtor.
         * 
         * @param scheduledSpecification HydraScheduledSpecification
         * @param isSelecionado Boolean
         */
        public HydraScheduledSpecificationRowData(HydraScheduledSpecification scheduledSpecification, Boolean isSelecionado) {
            this.scheduledSpecification = scheduledSpecification;
            this.isSelecionado = isSelecionado;
            this.dataExecucao = new Date();
        }

        private HydraScheduledSpecification scheduledSpecification;

        private Boolean isSelecionado;

        private Date dataExecucao;

        /**
         * @return o status (Ativado/Desativado).
         */
        public String getStatus() {
            if (this.scheduledSpecification.isEnabled()) {
                return ATIVADO;
            } else {
                return DESATIVADO;
            }
        }

        /**
         * @return o mnemonico do Emissor
         */
        public String getEmissor() {
            if (this.scheduledSpecification.getSenderRegistry() != null) {
                return this.scheduledSpecification.getSenderRegistry().getMnemonico();
            }
            return null;
        }

        /**
         * @return a descrição do emissor.
         */
        public String getDescricaoEmissor() {
            return this.scheduledSpecification.getSenderRegistry() == null ? "" : this.scheduledSpecification.getSenderRegistry()
                    .toString();
        }

        /**
         * @return the isSelecionado
         */
        public Boolean getIsSelecionado() {
            return this.isSelecionado;
        }

        /**
         * @param isSelecionado the isSelecionado to set
         */
        public void setIsSelecionado(Boolean isSelecionado) {
            this.isSelecionado = isSelecionado;
        }

        /**
         * @return the scheduledSpecification
         */
        public HydraScheduledSpecification getScheduledSpecification() {
            return this.scheduledSpecification;
        }

        /**
         * @param scheduledSpecification the scheduledSpecification to set
         */
        public void setScheduledSpecification(HydraScheduledSpecification scheduledSpecification) {
            this.scheduledSpecification = scheduledSpecification;
        }

        /**
         * Método busca uma lista de {@link HydraRequestImpl} e retorna a mais recente.
         * 
         * @return a última {@link HydraRequestImpl}
         * @throws WebWicketException sobe mensagem de exceção.
         */
        public HydraRequestImpl getUltimaRequisicao() throws WebWicketException {
            List<? extends HydraRequest> hydraRequests = null;
            HydraRequestDAO dao =
                    ConsultaIntegracaoEspecificacaoAgendamento.this.hydraController.getDAOFactory().getDAOByClass(HydraRequestDAO.class);
            hydraRequests = dao.findByScheduledSpecificationStatus(this.scheduledSpecification, null);
            if (hydraRequests.size() <= 0) {
                throw new WebWicketException(ERRO_SCHEDULED_SPECIFICATION_SEM_REQUESTS.create());
            }
            return (HydraRequestImpl) hydraRequests.get(0);
        }

        /**
         * @return the dataExecucao
         */
        public Date getDataExecucao() {
            return this.dataExecucao;
        }

        /**
         * @param dataExecucao the dataExecucao to set
         */
        public void setDataExecucao(Date dataExecucao) {
            this.dataExecucao = dataExecucao;
        }

        /**
         * Executa o {@link HydraScheduledSpecification} na data selecionada (dataExecucao).
         * 
         * @throws WebWicketException sobe mensagem de exceção.
         */
        public void executar() throws WebWicketException {
            if (this.dataExecucao != null) {
                // XXX (renan): substituir o metodo refresh
                ConsultaIntegracaoEspecificacaoAgendamento.this.hydraController.getSessionFactory().getCurrentSession()
                        .refresh(this.scheduledSpecification, LockMode.NONE);
                ConsultaIntegracaoEspecificacaoAgendamento.this.hydraController.send(this.dataExecucao, this.scheduledSpecification);
            } else {
                throw new WebWicketException(ERRO_SCHEDULED_SPECIFICATION_PREENCHER_DATA.create(this.scheduledSpecification.getSystem(),
                        this.scheduledSpecification.getAction()));
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected MessageCreator getHelpTextCreator() {
        return HelpTextMessages.CONSULTA_INTEGRACAO_ESPECIFICACAO_AGENDAMENTO;
    }
}